// 此处引入axios官方文件
import Axios from "axios"
import Qs from "qs"
// 取消重复请求接口集合
import {
  addPendingRequest,
  removePendingRequest,
  cancelSources,
} from "./util/CancelRepeatRquest.js"
import { errorAgainRequest, loopAgainRequest, retryDelayDefault } from "./util//RequestAgainSend.js" // 请求重发
import { cacheReqInterceptor, cacheResInterceptor } from "./util//RequestCache.js"
import { getTimestamp, isJsonStr } from "./util/ParamsUtil.js"
//空方法
function noop(a, b, c) {}

//扩展类
class ScrewAxios {
  //res 默认处理映射
  responseHandle = {
    200: response => {
      return response.data
    },
    401: response => {
      return Promise.reject(response)
    },
    404: response => {
      return Promise.reject(response)
    },
    500: response => {
      return Promise.reject(response)
    },
    default: response => {
      console.error("网络异常", response)
      return Promise.reject(response)
    },
  }
  headers = {
    "Cache-Control": "no-cache",
    Pragma: "no-cache",
  }
  constructor(opts = {}) {
    this.ins = null //声明一个axios实例
    this.baseURL = opts.baseURL || ""
    //是否可以重复，这个值一旦设置成true，相同url和参数的请求则不允许重复请求
    this.canRepeat = opts.canRepeat === undefined ? true : opts.canRepeat
    //是否启用时间戳，如果这个开启，则在每个请求上追加时间戳
    this.hasTimestamp = opts.hasTimestamp === undefined ? false : opts.hasTimestamp
    this.timeout = opts.timeout || 5000
    this.headers = Object.assign({}, this.headers, opts.headers)
    this.reqInterceptor = opts.reqInterceptor || noop
    this.resInterceptor = opts.resInterceptor || noop
    this.retry = opts.retry || 0
    this.retryDelay = opts.retryDelay || retryDelayDefault //设置重试间隔时间
    //扩展默认配置
    this.responseHandle = Object.assign({}, this.responseHandle, opts.responseHandle)
    this.init()
  }

  //初始化函数
  init() {
    //创建axios实例
    this.ins = Axios.create({
      baseURL: this.baseURL,
      timeout: this.timeout,
      headers: this.headers,
    })

    //设置request拦截器
    this.requestInterceptors()
    //设置response拦截器
    this.responseInterceptors()
  }

  //request 拦截器
  requestInterceptors() {
    //axios的方法
    this.ins.interceptors.request.use(
      config => {
        //是否需要批量去重
        if (this.canRepeat === false) {
          config.cancelRequest = true
        }
        //得到method方法
        let methodStr = config.method.toLocaleLowerCase()
        if (methodStr === "post" || methodStr === "put" || methodStr === "patch") {
          // 参数统一处理，请求都使用data传参
          config.params = Object.assign(this.hasTimestamp ? getTimestamp() : {}, config.params)
          if (config.headers["Content-Type"] === "application/x-www-form-urlencoded") {
            config.data = Qs.stringify(config.data)
          }
        } else if (
          methodStr === "get" ||
          methodStr === "delete" ||
          methodStr === "head" ||
          methodStr === "options"
        ) {
          // 参数统一处理
          config.params = Object.assign(this.hasTimestamp ? getTimestamp() : {}, config.data)
        } else {
          console.error(`不允许的请求方法： ${config.method}`)
          throw new Error(`不允许的请求方法： ${config.method}`)
        }
        // pendding 中的请求，后续请求不发送（由于存放的peddingMap 的key 和参数有关，所以放在参数处理之后）
        addPendingRequest(config) // 把当前请求信息添加到pendingRequest对象中
        //  请求缓存
        cacheReqInterceptor(config, this.ins)
        //自定义的requestInterceptor
        this.reqInterceptor(config)
        return config
      },
      error => {
        return Promise.reject(error)
      }
    )
  }

  //request 拦截器
  responseInterceptors() {
    this.ins.interceptors.response.use(
      response => {
        // 响应正常时候就从pendingRequest对象中移除请求
        removePendingRequest(response)
        cacheResInterceptor(response)
        //执行repsonse扩展拦截器
        this.resInterceptor(response)
        return this.responseHandle[response.status || "default"](response)
      },
      error => {
        //得到错误编码
        let status = (error.response && error.response.status && error.response.status) || ""
        if (error.code === "ECONNABORTED" && error.message.indexOf("timeout") != -1) {
          status = "timeout"
        }

        //将错误给responseHandle
        this.responseHandle[status || "default"](error.response)

        // 从pending 列表中移除请求，去掉重复的请求
        removePendingRequest(error.config || {})
        // 需要特殊处理请求被取消的情况，如果请求不是手动取消的
        if (!Axios.isCancel(error)) {
          // 请求重发
          errorAgainRequest(error, this.ins, this.retry, this.retryDelay)
        }
        // 请求缓存处理方式
        if (Axios.isCancel(error)) {
          return Promise.resolve(error) // 返回结果数据
        }
        return Promise.reject(error)
      }
    )
  }
  //取消所有请求的方法
  cancelAll() {
    //遍历所有的source
    if (cancelSources) {
      Promise.resolve(function () {
        for (let key of cancelSources.keys()) {
          let source = cancelSources.get(key)
          if (source && source.cancel) {
            source.cancel("执行取消")
          }
        }
        cancelSources.clear()
      })
    }
  }
  getAxios() {
    return Axios
  }
  getCancelTokenSource() {
    return Axios.CancelToken.source()
  }

  axios(...args) {
    return this.ins(...args)
  }
  __transMethod(url, method, ...config) {
    let beans = {
      url,
      method,
    }
    if (config && config.length > 0) {
      beans.data = config[0]
      if (config[1]) {
        Object.assign(beans, config[1])
      }
    }
    return this.ins(beans)
  }
  get(url, ...config) {
    return this.__transMethod(url, "get", ...config)
  }
  delete(url, ...config) {
    return this.__transMethod(url, "delete", ...config)
  }
  head(url, ...config) {
    return this.__transMethod(url, "head", ...config)
  }
  options(url, ...config) {
    return this.__transMethod(url, "options", ...config)
  }

  post(url, ...args) {
    return this.ins.post(url, ...args)
  }
  put(url, ...args) {
    return this.ins.put(url, ...args)
  }
  patch(url, ...args) {
    return this.ins.patch(url, ...args)
  }
}

export default ScrewAxios
